#include "D3DHelper.h"
#include "mymath.h"

HRESULT CD3DHelper::CreateBuffer(ID3D11Device* pDevice, void* pData, UINT szElement, UINT nElements, ID3D11Buffer*& pBuffer, DWORD bindFlags)
{
	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = szElement * nElements;
	bd.BindFlags = bindFlags;
	bd.CPUAccessFlags = 0;
	bd.StructureByteStride = szElement;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = pData;
	HRESULT hr = pDevice->CreateBuffer( &bd, &InitData, &pBuffer );
	return hr;

}

HRESULT CD3DHelper::CreateVertexBuffer(ID3D11Device* pDevice, void* vertices, UINT szVertex, UINT nVertices, ID3D11Buffer*& pVertexBuffer)
{
	return CreateBuffer(pDevice, vertices, szVertex, nVertices, pVertexBuffer, D3D11_BIND_VERTEX_BUFFER);
}



HRESULT CD3DHelper::CreateIndexBuffer(ID3D11Device* pDevice, void* ind, UINT szIndex, UINT nIndex, ID3D11Buffer*& pIndexBuffer)
{
	return CreateBuffer(pDevice, ind, szIndex, nIndex, pIndexBuffer, D3D11_BIND_INDEX_BUFFER);

}

HRESULT CD3DHelper::CreateInputLayout(ID3D11Device* pDevice,const D3D11_INPUT_ELEMENT_DESC* layout, UINT numElements, ID3DX11EffectPass* pEffectPass, ID3D11InputLayout*& pInputLayout)
{
	D3DX11_PASS_SHADER_DESC effectVsDesc;
	pEffectPass->GetVertexShaderDesc(&effectVsDesc);
	D3DX11_EFFECT_SHADER_DESC effectVsDesc2;
	effectVsDesc.pShaderVariable->GetShaderDesc(effectVsDesc.ShaderIndex, &effectVsDesc2);
	const void *vsCodePtr = effectVsDesc2.pBytecode;
	unsigned vsCodeLen = effectVsDesc2.BytecodeLength;


	return pDevice->CreateInputLayout(layout , numElements, vsCodePtr, vsCodeLen, &pInputLayout );
}

ID3D11DeviceContext* CD3DHelper::GetImmediateContext(ID3D11Device* pDevice)
{
	ID3D11DeviceContext* pContext;
	pDevice->GetImmediateContext(&pContext);
	return pContext;
}

HRESULT CD3DHelper::CreateEffectFromFile(ID3D11Device* pDevice, char* pSrcFile, ID3DX11Effect*& pEffect)
{
	ID3D10Blob *effectBlob = NULL, *errorsBlob = NULL;
	HRESULT hr = D3DX11CompileFromFile(
		pSrcFile, 0, 0, 0, "fx_5_0", 0, 0, 0, &effectBlob, &errorsBlob, 0);

	if FAILED(hr)
	{
		CONSOLE("Failed To compile %s fx file.\n error log: %s\n", pSrcFile, (char*)errorsBlob->GetBufferPointer());
		return hr;
	}

	hr = D3DX11CreateEffectFromMemory(
		effectBlob->GetBufferPointer(), effectBlob->GetBufferSize(), 0, pDevice, &pEffect, D3D_FEATURE_LEVEL_10_0);

	return hr;
}

CD3DHelper::CD3DHelper( ID3D11Device* pDevice ) : m_UintClearFX(pDevice)
{
	
}

HRESULT CD3DHelper::ClearRenderTargetViewUint( ID3D11DeviceContext* pContext, ID3D11RenderTargetView* pRTToClear, UINT clrColor[4] )
{
	ID3D11RenderTargetView* pOldRenderTargetViews[8];
	ID3D11DepthStencilView* pOldDS;
	pContext->OMGetRenderTargets(8, pOldRenderTargetViews, &pOldDS);
	pContext->OMSetRenderTargets(1, &pRTToClear, NULL);
	m_UintClearFX.Render(clrColor);
	pContext->OMSetRenderTargets(8, pOldRenderTargetViews, pOldDS);

	return S_OK;
}

ID3D11Texture2D* CD3DHelper::CreateTextureFile(ID3D11Device* pDevice, string FileName)
{
	ID3D11Texture2D* pTex = NULL;
	HRESULT hr = S_OK;
	D3DX11CreateTextureFromFile(pDevice, FileName.c_str(), NULL, NULL, (ID3D11Resource**)&pTex, &hr);

	if (FAILED(hr))
	{
		assert(0);
	}

	return pTex;
}

UINT CD3DHelper::GetNumPassesInTechByIndex( ID3DX11Effect* pEffect, UINT TechIndex, HRESULT* hr /*= NULL*/ )
{
	D3DX11_TECHNIQUE_DESC Desc;
	HRESULT _hr = S_OK;
	HRESULT*& pReturnHR = hr;
	_hr = pEffect->GetTechniqueByIndex(TechIndex)->GetDesc(&Desc);

	pReturnHR = (hr) ? hr : &_hr;

	if (FAILED(_hr))
	{
		*pReturnHR = _hr;
	}
	else
	{
		*pReturnHR = _hr;
		return Desc.Passes;
	}
}

HRESULT CD3DHelper::CreateDSBufferAndView( ID3D11Device* pDevice, UINT width, UINT height, DXGI_FORMAT format, ID3D11Texture2D*& pDS, ID3D11DepthStencilView*& pDSV )
{
	HRESULT hr = S_OK;
	D3D11_TEXTURE2D_DESC DSDesc;
	DSDesc.ArraySize = 1;
	DSDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	DSDesc.CPUAccessFlags = 0;
	DSDesc.Format = format;
	DSDesc.Height = height;
	DSDesc.Width = width;
	DSDesc.MipLevels = 1;
	DSDesc.MiscFlags = 0;
	DSDesc.SampleDesc.Count = 1;
	DSDesc.SampleDesc.Quality = 0;
	DSDesc.Usage = D3D11_USAGE_DEFAULT;
	
	hr = pDevice->CreateTexture2D(&DSDesc, NULL, &pDS);
	
	if(FAILED(hr))
	{
		CONSOLE("failed to create DS\n");
		return hr;
	}

	hr = pDevice->CreateDepthStencilView(pDS, NULL, &pDSV);

	if(FAILED(hr))
	{
		CONSOLE("failed to create DSV\n");
		return hr;
	}

	return hr;
	
}

CUintClearFX::CUintClearFX(ID3D11Device* pDevice) : m_pDevice(pDevice)
{
	vec3 vertices[] = { vec3(-1, -1, 0.5), vec3(-1, 1, 0.5), vec3(1,1,0.5), vec3(1,-1,0.5) } ;
	D3D11_INPUT_ELEMENT_DESC layout[] = {{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, };
	UINT numElements = ARRAYSIZE(layout);
	CD3DHelper::CreateEffectFromFile(m_pDevice, "..\\Shaders\\Clear.fx", m_pEffect);
	CD3DHelper::CreateVertexBuffer(m_pDevice, vertices, sizeof(vec3), ARRAYSIZE(vertices), m_pVertexBuffer);

	ID3DX11EffectPass* pEffectPass = m_pEffect->GetTechniqueByIndex(0)->GetPassByIndex(0);
	CD3DHelper::CreateInputLayout(m_pDevice, layout, numElements, pEffectPass, m_pInputLayout);
}

void CUintClearFX::Render( UINT clrColor[4] )
{
	ID3D11DeviceContext* pContext = CD3DHelper::GetImmediateContext(m_pDevice);
	UINT stride = sizeof(vec3);
	UINT offset = 0;

	pContext->IASetInputLayout(m_pInputLayout);
	pContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );
	pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
	ID3DX11EffectPass* pEffectPass = m_pEffect->GetTechniqueByIndex(0)->GetPassByIndex(0);
	m_pEffect->GetVariableByName("clrColor")->AsVector()->SetIntVector((int*)clrColor);
	pEffectPass->Apply(0, pContext);
	pContext->Draw(4, 0);
}

